package top.syfy.bili.fbm.main;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.setting.dialect.Props;
import top.syfy.bili.fbm.entry.Entry;
import top.syfy.bili.fbm.entry.PageData;
import top.syfy.bili.fbm.util.DateTimeNowUtil;
import top.syfy.bili.fbm.util.EntryJSONUtil;
import top.syfy.bili.fbm.util.FfmpegUtil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * 主启动类
 */
public class MainEnter {

	public static void main(String[] args) throws IOException, InterruptedException {
		System.out.println(DateTimeNowUtil.now() + " : 正在初始化...");
		// ffmpeg可执行文件的绝对路径
		String ffmpeg;
		// 专辑存放目录（该目录下有多个"缓存视频的存储目录）的绝对路径
		String inPath;
		// 输出目录的绝对路径
		String outPath;
		// 读取properties配置文件
		File propertiesFile = new ClassPathResource("entry.properties").getFile();
		if (!FileUtil.exist(propertiesFile)) {
			throw new FileNotFoundException(propertiesFile.getAbsolutePath() + " 文件不存在");
		}
		Props props = new Props(propertiesFile, StandardCharsets.UTF_8);
		props.autoLoad(true);
		// 初始化
		ffmpeg = props.getProperty("FFMPEG");
		inPath = props.getProperty("IN_PATH");
		outPath = props.getProperty("OUT_PATH");
		//判断是否已设置属性
		if (StrUtil.isBlank(ffmpeg) || StrUtil.isBlank(inPath) || StrUtil.isBlank(outPath)) {
			throw new RuntimeException("缺少必要的参数: ffmpeg / inPath / outPath");
		}
		// 专辑存放目录(多个专辑存放的目录)
		File cacheDir = new File(inPath);
		if (!FileUtil.exist(cacheDir)) {
			throw new FileNotFoundException(cacheDir.getAbsolutePath() + " 不存在");
		}
		if (!FileUtil.isDirectory(cacheDir)) {
			throw new IOException(cacheDir.getAbsolutePath() + "应该是一个目录, 但它不是");
		}
		System.out.println(DateTimeNowUtil.now() + " : 初始化完成");
		/*
		    遍历获取专辑并将读取到的信息写出到磁盘（json格式的文件）
		 */
		System.out.println(DateTimeNowUtil.now() + " : 开始读取缓存文件的配置信息");
		File[] videos = cacheDir.listFiles(File::isDirectory);
		if (Objects.isNull(videos)) {
			throw new RuntimeException(cacheDir.getAbsolutePath() + " 下没有符合条件的专辑存放目录");
		}
		Arrays.sort(videos, Comparator.comparing(File::getName));
		for (File video : videos) {
			Entry entry = EntryJSONUtil.parseEntryJSONFile(propertiesFile, video);
			// 在读取完成之后, 写出到文件,格式为: {avId}.json
			String jsonStr = JSONUtil.parseObj(entry, false, true).toStringPretty();
			File writeJSON = new File(outPath, entry.getAvId() + ".json");
			FileWriter writer = new FileWriter(writeJSON, StandardCharsets.UTF_8);
			writer.write(jsonStr);
		}
		System.out.println(DateTimeNowUtil.now() + " : 读取缓存文件的配置信息完成");
		/*
		    读取对应的JSON文件并进行合并
		 */
		System.out.println(DateTimeNowUtil.now() + " : 开始合并...");
		File writeOutDir = new File(outPath);
		if (!FileUtil.exist(writeOutDir)) {
			System.out.println(DateTimeNowUtil.now() + " : 输出目录不存在，创建输出目录");
			FileUtil.mkParentDirs(writeOutDir);
		}
		if (!FileUtil.isDirectory(writeOutDir)) {
			throw new IOException(writeOutDir.getAbsolutePath() + " 它不是一个目录");
		}
		File[] jsonFiles = writeOutDir.listFiles(f -> f.getName().endsWith(".json"));
		if (Objects.isNull(jsonFiles)) {
			throw new RuntimeException("该目录下不存在json文件");
		}
		Process process;
		for (File jf : jsonFiles) {
			JSONObject obj = JSONUtil.readJSONObject(jf, StandardCharsets.UTF_8);
			Entry entry = JSONUtil.toBean(obj, Entry.class);
			List<PageData> pds = entry.getPds();
			// 创建专辑目录
			File dir = FileUtil.mkdir(new File(outPath, entry.getTitle()));
			for (PageData pd : pds) {
				// 注意: 此文件绝对不能预先创建好或者已存在, 否则将不会合并出新文件
				File outFile = new File(dir, pd.getPart() + props.getProperty("MERGED_SUFFIX"));
				System.out.println(DateTimeNowUtil.now() + " : " + outFile.getName() + " 合并中...");
				process = FfmpegUtil.mergeM4S(
					ffmpeg,
					pd.getVideoPart(),
					pd.getAudioPart(),
					outFile.getAbsolutePath()
				);
				assert process != null;
				process.waitFor();
				FfmpegUtil.destroy(process);
				System.out.println(DateTimeNowUtil.now() + " : " + outFile.getName() + " 合并完成\n");
			}
		}
		System.out.println(DateTimeNowUtil.now() + " : 合并完成");
		System.exit(0);
	}

}
